<?php
/**
 * 语言列表
 *
 * @author Zeon <scplay@gmail.com>
 * @date 2019/5/28 14:36
 * @copyright PanxSoft Inc.
 */

namespace App\Http\Controllers\Common;


use App\Http\Controllers\ApiController;
use App\Services\AliYun\OSS;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Str;

class OSSController extends ApiController
{
    const ROUTES = [
        'callback' => 'api.common.oss.callback',
        'webSign'  => 'api.common.oss.webSign',
    ];

    /**
     * @param Request $request
     * @param OSS $oss
     *
     * @return array|Response
     * @throws \Exception
     */
    public function webSign(Request $request, OSS $oss)
    {
        $dir = Str::finish($request->get('dir') ?: 'misc/', '/') ;

        $use_callback = (bool) $request->get('use_callback');

        return $this->response($oss->webUploaderSign($dir, $use_callback));
    }

    /**
     * 前端直传回调，参考文档
     *
     * @link https://help.aliyun.com/document_detail/91771.html?spm=a2c4g.11186623.2.17.19c06e28Hq2asb#concept-nhs-ldt-2fb
     *
     * @param Request $request
     *
     * @return array|\Illuminate\Http\Response
     */
    public function callback(Request $request)
    {
//         调试
//         logger((string) $request);
//         logger(getenv());

        // 1. 获取 OSS 的签名
        $authorizationBase64 = $request->header('Authorization');
        if (! $authorizationBase64) {
            return abort(Response::HTTP_FORBIDDEN, 'Authorization Header Not Found');
        }
        $authorization = base64_decode($authorizationBase64);

        // 2. 获取公钥 URL, 并请求回公钥
        $pubKeyUrlBase64 = $request->header('X-Oss-Pub-Key-Url');
        if (! $pubKeyUrlBase64) {
            return abort(Response::HTTP_FORBIDDEN, 'OSS PubKey URL Header Not Found');
        }
        $pubKey = $this->tryRequestUrl(base64_decode($pubKeyUrlBase64));
        if (! $pubKey) {
            return abort(Response::HTTP_FORBIDDEN, 'OSS PubKey URL Request Error');
        }

        // 3. 获取当前请求 路径参数 + body 拼接待签名字符串（如果此接口 path 中特殊字符，需要先 url encode "?" 之前的路径）
        $authStr = $request->getRequestUri() . "\n" . $request->getContent();

        // 4. 验证签名
        $ok = openssl_verify($authStr, $authorization, $pubKey, OPENSSL_ALGO_MD5);
        if ($ok === 1) {
            return $this->responseJson(["Status" => "Ok"]);
        } else {
            return abort(Response::HTTP_FORBIDDEN, 'OpenSSL verify failed');
        }
    }

    /**
     * @param string $url
     *
     * @return false|string
     */
    private function tryRequestUrl(string $url): ?string
    {
        try {
            return file_get_contents($url);
        } catch (\Exception $exception) {
            logger($exception->getMessage());
            return null;
        }
    }
}